﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Application
{
	public class CommandParser
	{
		private List<int> Q = new List<int> (){ 0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,18,19,20,21,22,23,24,25, 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43 };
		private List<char> E = new List<char>();
		private List<int> F = new List<int>(){0};
		private Dictionary<string,int> B = new Dictionary<string, int>();
		private int q0 = 1;
        private string grammaPath = "";
        public event Action<object, ErrorCommandEventArgs> ErrorCommand;

	   public CommandParser (GrammaType type)
		{
          switch(type)
          {
              case GrammaType.DatabasesAndTables:
                  grammaPath = "c://dbsGrammas/db.txt";
                  break;

              case GrammaType.Record:
                  grammaPath = "c://dbsGrammas/rec.txt";
                  break;
          }




          CreateE(type);
          CreateB(type);
		}

		private void CreateE(GrammaType type)
		{
            if (type == GrammaType.DatabasesAndTables)
            {
                for (int i = 'a'; i <= 'z'; i++)
                {
                    E.Add((char)i);
                    B.Add((13 + " - " + (char)i).ToString(), 13);
                    B.Add((43 + " - " + (char)i).ToString(), 43);
                }
                E.Add('*');
                E.Add(':');
                E.Add('/');
                E.Add('.');
                E.Add('@');
                B.Add((13 + " - " + ':').ToString(), 13);
                B.Add((13 + " - " + '*').ToString(), 13);
                B.Add((13 + " - " + '/').ToString(), 13);
                B.Add((13 + " - " + '.').ToString(), 13);
                B.Add((13 + " - " + '@').ToString(), 13);
                B.Add((43 + " - " + '.').ToString(), 43);
                B.Add((43 + " - " + '@').ToString(),43);
                for (int i = 0; i <= 9; i++)
                {
                    E.Add((char)i);
                    B.Add((13 + " - " + i).ToString(), 13);
                    B.Add((43 + " - " + i).ToString(), 43);
                }

                B.Add("10 -  ", 10);
                B.Add("12 -  ", 12);
                B.Add("18 -  ", 18);
                B.Add("24 -  ", 24);
                B.Add("28 -  ", 28);
                B.Add("32 -  ", 32);
                B.Add("39 -  ", 39);
                B.Add("42 -  ", 42);
            }
            else if (type == GrammaType.Record)
            {
                for (int i = 'a'; i <= 'z'; i++)
                {
                    E.Add((char)i);
                    B.Add((30 + " - " + (char)i).ToString(), 30);
                    B.Add((33 + " - " + (char)i).ToString(), 33);
                    B.Add((25 + " - " + (char)i).ToString(), 25);
                }

                E.Add('*');
                B.Add((25 + " - " + '*').ToString(), 25);

                for (int i = 0; i <= 9; i++)
                {
                    E.Add((char)i);
                    B.Add((30 + " - " + i).ToString(), 30);
                    B.Add((33 + " - " + i).ToString(), 33);
                    B.Add((25 + " - " + i).ToString(), 25);
                }

                B.Add("8 -  ", 8);
                B.Add("12 -  ", 12);
                B.Add("18 -  ", 18);
                B.Add("22 -  ", 22);
                B.Add("24 -  ", 24);
                B.Add("37 -  ", 37);
                B.Add("43 -  ", 43);
            }
			
		}

        private void CreateB(GrammaType type)
		{
			string path_to_file = grammaPath;
			using (StreamReader sr = new StreamReader (path_to_file)) {

				while (!sr.EndOfStream) {
					var line = sr.ReadLine ();
					B.Add (line.Split ('~') [0].Trim (), int.Parse (line.Split ('~') [1].Trim ()));
				}

			}
		}

		private int GetState(int state, char alph)
		{
			if (B.ContainsKey (state.ToString () + " - " + alph)) {
				return B.FirstOrDefault (x => x.Key == (state.ToString () + " - " + alph)).Value;
			}
			return -1;
		}

		public bool ifCorrect(string letter)
		{
			Stack<int> s = new Stack<int> ();
			s.Push (q0);

			for (int i = 0; i < letter.Length; i++) {

				var f = s.Peek ();

				foreach (var it in Q) {
					if (it == f) {
						var state = GetState (f, letter [i]);

						if (state != -1) {
							s.Push (state);
						} else {
                            if (ErrorCommand != null)
                                ErrorCommand(this, new ErrorCommandEventArgs(letter, i, f));
							return false;
						}
					}
				}

			}
				var fin = s.Peek ();

				foreach (var it in F) {
					if (fin == it)
						return true;
				}

                if (ErrorCommand != null)
                    ErrorCommand(this, new ErrorCommandEventArgs(letter, fin, fin));
				return false;

			}

		}

         public enum GrammaType
    {
        DatabasesAndTables,
        Record
    }

            public class ErrorCommandEventArgs : EventArgs
            {
                public string Command { get; set; }
                public int ErrorIndexCommand { get; set; }

                public int State { get; set; }

                public ErrorCommandEventArgs(string command, int index, int state)
                {
                    Command = command;
                    ErrorIndexCommand = index;
                    State = state;
                }
            }
	}


